package com.mind.adjust.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.mind.adjust.service.AjObjectService;
import com.mind.common.core.domain.AjaxResult;
import com.mind.common.core.redis.RedisCache;
import com.mind.common.log.annotation.Log;
import com.mind.common.log.enums.BusinessType;
import com.mind.common.utils.StringUtils;
import com.mind.common.utils.poi.ExcelUtil;
import com.mind.common.utils.poi.ImportExcelResult;
import com.mind.common.utils.poi.ValidationUtils;
import com.mind.common.web.controller.BaseController;
import com.mind.common.web.page.TableDataInfo;
import com.mind.customer.utils.CountUtils;
import com.mind.customer.utils.InterfaceUtil;
import com.mind.system.domain.AjObject;
import com.mind.system.domain.SysConfig;
import com.mind.system.mapper.SysConfigMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 智能审核模块/审核模块/对象管理
 *
 * @author makejava
 * @DocView.PathPrefix {{host}}/api/adjust
 * @since 2024-07-11 17:40:10
 */
@RestController
@RequestMapping("adjust/object")
@Tag(name = "对象管理", description = "对象管理")
public class AjObjectController extends BaseController {
    /**
     * 服务对象
     */
    @Autowired
    private AjObjectService ajObjectService;
    @Resource
    private SysConfigMapper sysConfigMapper;
    @Resource
    private CountUtils countUtils;
    @Autowired
    private RedisCache redisCache;
    private String ncUrl;
    private String ncSecret;
    private String ncUserName;
    private String ncPwd;

    /**
     * 获取对象列表
     *
     * @param object 筛选条件
     * @return com.mind.system.domain.AjObject
     */
    @PreAuthorize("@ss.hasPermi('adjust:object:list')")
    @Log(title = "对象列表", businessType = BusinessType.QUERY)
    @GetMapping("/list")
    @Operation(summary = "对象列表", description = "对象列表")
    public TableDataInfo list(AjObject object) {
        startPage();
        List<AjObject> list = ajObjectService.selectObjectList(object);
        return getDataTable(list);
    }

    /**
     * 对象导入
     *
     * @return 结果
     */
//    @RequiresPermissions("adjust:object:import")
    @Log(title = "对象导入", businessType = BusinessType.IMPORT)
    @PostMapping("/import")
    @Operation(summary = "对象导入", description = "对象导入")
    public AjaxResult importExcel(MultipartFile file) throws IOException {
        List<AjObject> cachedDataList = new ArrayList<>();
        List<ImportExcelResult> errorList = new ArrayList<>();
        EasyExcel.read(file.getInputStream(), AjObject.class, new ReadListener<AjObject>() {

            @Override
            public void invoke(AjObject data, AnalysisContext context) {
                Set<ConstraintViolation<AjObject>> violations = ValidationUtils.getValidator().validate(data);
                if (violations.size() > 0) {
                    throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), 0, null, null, "");
                }
                cachedDataList.add(data);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                saveData();
            }

            /**
             * 加上存储数据库
             */
            private void saveData() {
                int i = ajObjectService.batchInsert(cachedDataList);
            }

            /**
             * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
             *
             * @param exception
             * @param context
             * @throws Exception
             */
            @Override
            public void onException(Exception exception, AnalysisContext context) {
                // 如果是某一个单元格的转换异常 能获取到具体行号
                // 如果要获取头的信息 配合invokeHeadMap使用
                if (exception instanceof ExcelDataConvertException) {
                    ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
                    String errMsg = String.format("第%d行数据验证异常", excelDataConvertException.getRowIndex());
                    errorList.add(new ImportExcelResult() {{
                        setRow(excelDataConvertException.getRowIndex());
                        setCol(excelDataConvertException.getColumnIndex());
                        setError(errMsg);
                    }});
                }
            }
        }).sheet().doRead();
        if (errorList.size() > 0) {
            return AjaxResult.success(String.format("一共%d条，成功导入%d条，错误%d条。错误详情：%s", cachedDataList.size() + errorList.size(), cachedDataList.size(), errorList.size(), errorList.stream().map(ImportExcelResult::getError).collect(Collectors.joining("\r\n"))));
        } else {
            return AjaxResult.success(String.format("一共%d条，成功导入%d条，错误0条。", (cachedDataList.size()), cachedDataList.size()));
        }
    }

    /**
     * 附件类型下载模板
     *
     * @return 结果
     */
    @Log(title = "对象下载模板", businessType = BusinessType.DOWNLOAD)
//    @RequiresPermissions("adjust:attachType:download")
    @GetMapping("/downloadTemplate")
    @Operation(summary = "对象下载模板", description = "对象下载模板")
    public void downloadTemplate(HttpServletResponse response) throws IOException {
        ExcelUtil<AjObject> util = new ExcelUtil<>(AjObject.class);
        String fileName = URLEncoder.encode("对象模板", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        util.exportExcel(response, new ArrayList<>(), "对象数据");
    }

    /**
     * 对象导出
     *
     * @param object 筛选条件
     * @return 结果
     */
    @Log(title = "对象导出", businessType = BusinessType.EXPORT)
//    @RequiresPermissions("adjust:object:export")
    @PostMapping("/export")
    @Operation(summary = "对象导出", description = "对象导出")
    public void export(HttpServletResponse response, AjObject object) {
        List<AjObject> list = ajObjectService.selectObjectList(object);
        ExcelUtil<AjObject> util = new ExcelUtil<AjObject>(AjObject.class);
        util.exportExcel(response, list, "对象数据");
    }

    /**
     * 根据ID获取对象详情
     *
     * @return com.mind.system.domain.AjObject
     */
//    @RequiresPermissions("adjust:object:query")
    @GetMapping(value = "/{objectId}")
    @Operation(summary = "获取对象详情", description = "获取对象详情")
    public AjaxResult getInfo(@PathVariable Long objectId) {
        return success(ajObjectService.selectObjectById(objectId));
    }

    /**
     * 新增对象
     *
     * @return 结果
     */
//    @RequiresPermissions("adjust:object:add")
    @Log(title = "对象新增", businessType = BusinessType.INSERT)
    @PostMapping
    @Operation(summary = "对象新增", description = "对象新增")
    public AjaxResult add(@Validated @RequestBody AjObject object) {
        return toAjax(ajObjectService.insertObject(object));
    }

    /**
     * 修改对象
     *
     * @return 结果
     */
    @PreAuthorize("@ss.hasPermi('adjust:object:edit')")
    @Log(title = "对象修改", businessType = BusinessType.UPDATE)
    @PutMapping
    @Operation(summary = "对象修改", description = "对象修改")
    public AjaxResult edit(@Validated @RequestBody AjObject object) {
        return toAjax(ajObjectService.updateObject(object));
    }

    /**
     * 同步对象到NC
     *
     * @return 结果
     */
    @PostMapping("/syncTonc")
    @Operation(summary = "同步对象到NC", description = "同步对象到NC")
    public AjaxResult syncObjectToNc(@Parameter(description = "对象Id", required = true) Long[] objectIds) {
        int num = 0;
        // 判断Nc信息
        /*if(ncUrl==null){
            initNCData();
        }*/
        initNCData();
        // 获取token
        try {
            ncSecret = InterfaceUtil.ncGetToken(redisCache, ncUserName, ncPwd, countUtils, ncUrl + "/api/auth/login");
        } catch (Exception e) {
            e.printStackTrace();
        }
        for (Long objId : objectIds) {
            AjObject object = ajObjectService.selectObjectById(objId);
            if (object != null && object.getType().equals("Datasource")) {//附件
                num = createNcObject(object, "default");
            } else if (object != null && object.getType().equals("OriginalOrder")) {//单据
                num = createNcObject(object, "virtual");

                String nc_url = "";
                boolean is_sourceId = true;
                JSONObject params = new JSONObject();
                params.put("name", object.getAttachCate());
                List<Integer> ls_sourceId = new ArrayList<>();
                if (object.getAttachType() != null && object.getAttachType().length() > 0) {
                    String[] ls_type = object.getAttachType().split(",");
                    for (String type : ls_type) {
                        ls_sourceId.add(Integer.parseInt(type));
                        // 判断是否添加到附件类型
                        /*if(Integer.parseInt(type)==object.getSourceId()){
                            is_sourceId = false;
                        }*/
                    }
                }
                /*if(is_sourceId){
                    if(object.getAttachType().length()>0){
                        object.setAttachType(object.getAttachType()+","+object.getSourceId());
                    }else{
                        object.setAttachType(object.getSourceId().toString());
                    }
                }*/
                ls_sourceId.add(Integer.parseInt(object.getSourceId().toString()));
                params.put("sourceIds", ls_sourceId);

                // 判断修改还是添加
                if (object.getNcScenarioid() != null && object.getNcScenarioid().length() > 0) { //判断是否已经同步过
                    nc_url = ncUrl + "/api/nc-scenario/update";
                    params.put("id", Integer.parseInt(object.getNcScenarioid()));
                } else {
                    nc_url = ncUrl + "/api/nc-scenario/create";
                }
                try {
                    JSONObject result = InterfaceUtil.ncPostRequst(nc_url, ncSecret, countUtils, params, object.getType());
                    // 判断是否同步成功
                    if (result.getJSONObject("data").getString("id") != null && result.getJSONObject("data").getString("id").length() > 0) {
                        num = 1;
                        if (nc_url.indexOf("create") != -1) {
                            object.setNcScenarioid(result.getJSONObject("data").getString("id"));

                            ajObjectService.updateObject(object);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    // 返回错误信息
                    return error(e.getMessage());
                }
            }
        }
        return toAjax(num);
    }

    /**
     * 删除对象
     *
     * @return 结果
     */
    @PreAuthorize("@ss.hasPermi('adjust:object:remove')")
    @Log(title = "对象删除", businessType = BusinessType.DELETE)
    @DeleteMapping("/{objectIds}")
    @Operation(summary = "对象删除", description = "对象删除")
    public AjaxResult remove(@Parameter(description = "对象Id", required = true) @PathVariable Long[] objectIds) {
        return toAjax(ajObjectService.deleteObjectByIds(objectIds));
    }

    /**
     * 初始化NC数据
     */
    private void initNCData() {
        SysConfig ncUrlConfig = sysConfigMapper.checkConfigKeyUnique("NC_URL");
        if (ncUrlConfig != null && StringUtils.isNotEmpty(ncUrlConfig.getConfigValue())) {
            ncUrl = ncUrlConfig.getConfigValue();
        } else {
            ncUrl = "http://nd.fanhaninfo.test";
        }
        SysConfig ncUserNameConfig = sysConfigMapper.checkConfigKeyUnique("NC_USER_NAME");
        if (ncUserNameConfig != null && StringUtils.isNotEmpty(ncUserNameConfig.getConfigValue())) {
            ncUserName = ncUserNameConfig.getConfigValue();
        }
        SysConfig ncPwdConfig = sysConfigMapper.checkConfigKeyUnique("NC_PWD");
        if (ncPwdConfig != null && StringUtils.isNotEmpty(ncPwdConfig.getConfigValue())) {
            ncPwd = ncPwdConfig.getConfigValue();
        }
    }

    /**
     * 同步NC对象
     *
     * @param object
     * @return
     */
    private int createNcObject(AjObject object, String type) {
        int num = 0;
        String nc_url = "";
        JSONObject params = new JSONObject();
        if (type.equals("default")) {
            //             附件同步nc 传分类名称
            params.put("name", object.getTypeName());
        } else {
            //             单据同步nc 传单据名称
            params.put("name", object.getAttachCate());
        }
        params.put("prompt", object.getTypeDesc());
        params.put("type", type);
        JSONArray fields = new JSONArray();
        // 拼接数据
        String str_fields = object.getFields();
        if (str_fields != null && str_fields.length() > 0) {
            JSONArray fieldArray = JSONArray.parseArray(str_fields);
            fieldArray.forEach(field -> {
                JSONObject fieldObj = (JSONObject) field;
                if (!fieldObj.get("ruleDataField").equals("对象是否存在")) {
                    JSONObject field_obj = new JSONObject();
                    field_obj.put("title", fieldObj.get("attachmentDataField"));
                    String fieldType = fieldObj.getString("fieldType");
                    String dataType = fieldObj.getString("dataType");
                    if (fieldType.equals("number")) {
                        field_obj.put("type", "float");
                    } else if (fieldType.equals("text")) {
                        field_obj.put("type", "str");
                    } else if (fieldType.equals("date")) {
                        field_obj.put("type", "str");
                    } else if (fieldType.equals("object") && dataType.equals("row")) {
                        field_obj.put("type", "table");
                        if (fieldObj.getJSONArray("children").size() > 0) {
                            field_obj.put("children", createNcChildren(fieldObj));
                        }
                    } else {
                        field_obj.put("type", "str");
                    }

                    field_obj.put("description", fieldObj.get("attachmentDataDesc") == null ? "" : fieldObj.get("attachmentDataDesc").toString());
                    // 是否可忽略
                    if (fieldObj.get("isIgnoreAttachmentData") != null && fieldObj.get("isIgnoreAttachmentData").toString().equals("true")) {
                        field_obj.put("ignore", true);
                    }
                    fields.add(field_obj);
                }
            });
            params.put("fields", fields);
        }
        // 判断修改还是添加
        if (object.getSourceId() != null && object.getSourceId() != 0) { //判断是否已经同步过
            nc_url = ncUrl + "/api/nc-source/update";
            params.put("id", object.getSourceId());
        } else {
            nc_url = ncUrl + "/api/nc-source/create";
        }
        try {
            JSONObject result = InterfaceUtil.ncPostRequst(nc_url, ncSecret, countUtils, params, object.getType());
            // 判断是否同步成功
            if (result.getJSONObject("data").getString("id") != null && result.getJSONObject("data").getString("id").length() > 0) {
                num = 1;
                if (nc_url.indexOf("create") != -1) {
                    object.setSourceId(result.getJSONObject("data").getLongValue("id"));
                    ajObjectService.updateObject(object);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return num;
    }

    /**
     * 获取下级字段
     *
     * @param object
     * @return
     */
    private JSONArray createNcChildren(JSONObject object) {
        JSONArray children = new JSONArray();
        if (object.getJSONArray("children").size() > 0) {
            object.getJSONArray("children").forEach(child -> {
                JSONObject fieldObj = (JSONObject) child;
                if (!fieldObj.get("ruleDataField").equals("对象是否存在")) {
                    JSONObject field_obj = new JSONObject();
                    field_obj.put("title", fieldObj.get("attachmentDataField"));
                    String fieldType = fieldObj.getString("fieldType");
                    String dataType = fieldObj.getString("dataType");
                    if (fieldType.equals("number")) {
                        field_obj.put("type", "float");
                    } else if (fieldType.equals("text")) {
                        field_obj.put("type", "str");
                    } else if (fieldType.equals("date")) {
                        field_obj.put("type", "str");
                    } else if (fieldType.equals("object") && dataType.equals("row")) {
                        field_obj.put("type", "table");
                        if (fieldObj.getJSONArray("children").size() > 0) {
                            field_obj.put("children", createNcChildren(fieldObj));
                        }
                    } else {
                        field_obj.put("type", "str");
                    }

                    field_obj.put("description", fieldObj.get("attachmentDataDesc") == null ? "" : fieldObj.get("attachmentDataDesc").toString());
                    // 是否可忽略
                    if (fieldObj.get("isIgnoreAttachmentData") != null && fieldObj.get("isIgnoreAttachmentData").toString().equals("true")) {
                        field_obj.put("ignore", true);
                    }
                    children.add(field_obj);
                }
            });
        }
        return children;
    }

}


